package com.springboot.distributed.transaction.util;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.support.DefaultTransactionStatus;

import com.springboot.common.util.SafeNullUtils;
import com.springboot.common.util.StringUtil;

/**
 * 分布式事务管理器
 *
 * @author supu
 * @date 2019-09-05 16:18
 **/
public class DistributedTransactionManager {
    private static final Logger LOGGER = LoggerFactory.getLogger(DistributedTransactionManager.class);

    /**
     * 线程事务消息
     */
    private static final ThreadLocal<TransactionInfo> THREAD_LOCAL_INFO = new ThreadLocal<>();

    /**
     * 线程事务map
     */
    private static final Map<String, DefaultTransactionStatusWrapper> THREAD_TRANSACTION_MAP = new ConcurrentHashMap<>(16);

    public static String getUniqueKey() {
        TransactionInfo transactionInfo = THREAD_LOCAL_INFO.get();
        return transactionInfo == null ? null : transactionInfo.getUniqueKey();
    }

    /**
     * 注册分布式事务
     *
     * @param uniqueKey
     * @param isHeader
     */
    public static void registerTransactionInfo(String uniqueKey, boolean isHeader) {
        TransactionInfo transactionInfo = THREAD_LOCAL_INFO.get() == null ? new TransactionInfo() : THREAD_LOCAL_INFO.get();
        transactionInfo.setUniqueKey(uniqueKey);
        transactionInfo.setHeader(isHeader);

        THREAD_LOCAL_INFO.set(transactionInfo);

        LOGGER.info("thread : {} register transactionInfo : {}", getThreadInfo(), transactionInfo);
    }

    private static String getThreadInfo() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(Thread.currentThread().getName()).append("-").append(Thread.currentThread().getId());
        return stringBuilder.toString();
    }

    /**
     * 是否注册了分布式事务
     *
     * @return
     */
    public static boolean hasRegisteredDistributedTransaction() {
        TransactionInfo transactionInfo = THREAD_LOCAL_INFO.get();
        return transactionInfo != null && StringUtil.isNotEmpty(transactionInfo.getUniqueKey());
    }

    /**
     * 根据key清除对应的事务状态列表
     */
    public static void clearDistributedTransaction(String uniqueKey) {
        THREAD_TRANSACTION_MAP.remove(uniqueKey);
    }

    /**
     * 清除分布式事务
     */
    public static void clear() {
        THREAD_LOCAL_INFO.remove();
    }

    /**
     * 保存事务状态并返回是否是事务入口
     *
     * @param transactionStatus
     * @return
     */
    public static boolean saveTransactionStatus(DefaultTransactionStatus transactionStatus) {
        TransactionInfo transactionInfo = THREAD_LOCAL_INFO.get();
        String uniqueKey = transactionInfo.getUniqueKey();
        if (THREAD_TRANSACTION_MAP.containsKey(uniqueKey)) {
            THREAD_TRANSACTION_MAP.get(uniqueKey).getTransactionStatusList().add(transactionStatus);
        } else {
            THREAD_TRANSACTION_MAP.put(uniqueKey, new DefaultTransactionStatusWrapper(transactionStatus));
        }

        return transactionInfo.isHeader();
    }

    /**
     * 根据key获取事务状态列表
     *
     * @param uniqueKey
     * @return
     */
    public static List<DefaultTransactionStatus> getDefaultTransactionStatusList(String uniqueKey) {
        return SafeNullUtils.safeGet(() -> THREAD_TRANSACTION_MAP.get(uniqueKey).getTransactionStatusList());
    }
}
